package com.clp.protocol.iec104.definition;

import com.clp.protocol.iec104.apdu.asdu.infoobj.infoelem.filetransfer.*;
import com.clp.protocol.core.utils.EnumElemDoesNotExistException;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 文件传输
 */
public interface Ft {
    /**
     * 附加数据包类型
     */
    @Getter
    @AllArgsConstructor
    enum AttachPackType {
        /**
         * 2为文件传输
         */
        FileTransfer(2);

        private final int val;

        public static AttachPackType gain(int val) {
            for (AttachPackType attachPackType : AttachPackType.values()) {
                if (attachPackType.val == val) {
                    return attachPackType;
                }
            }
            throw new EnumElemDoesNotExistException(AttachPackType.class);
        }
    }

    /**
     * 操作标识
     */
    @Getter
    @AllArgsConstructor
    enum OperationTag {
        /**
         * 文件目录召唤
         */
        FILE_READ_DIRE(1, FileReadDireAttachPack.class),
        /**
         * 文件目录召唤确认
         */
        FILE_READ_DIRE_CON(2, FileReadDireConAttachPack.class),
        /**
         * 读文件激活
         */
        FILE_READ_ACT(3, FileReadActAttachPack.class),
        /**
         * 读文件激活确认
         */
        FILE_READ_CON(4, FileReadConAttachPack.class),
        /**
         * 读文件数据传输
         */
        FILE_RDATA_RESP(5, FileRDataRespAttachPack.class),
        /**
         * 读文件数据传输确认
         */
        FILE_RDATA_CON(6, FileRDataConAttachPack.class),
        /**
         * 写文件激活
         */
        FILE_WRITE_ACT(7, FileWriteActAttackPack.class),
        /**
         * 写文件激活确认
         */
        FILE_WRITE_CON(8, FileWriteConAttachPack.class),
        /**
         * 写文件数据传输
         */
        FILE_WDATA_RESP(9, FileWDataRespAttachPack.class),
        /**
         * 写文件数据传输确认
         */
        FILE_WDATA_CON(10, FileWDataConAttachPack.class);

        private final int val;

        private final Class<? extends AttachPack> attachPackClass;

        public static OperationTag gain(int val) {
            for (OperationTag operationTag : OperationTag.values()) {
                if (operationTag.val == val) {
                    return operationTag;
                }
            }
            throw new EnumElemDoesNotExistException(OperationTag.class);
        }

        public AttachPack newInvalidAttachPack() {
            AttachPack retAttackPack = null;
            try {
                Constructor<? extends AttachPack> constructor = attachPackClass.getConstructor();
                constructor.setAccessible(true);
                retAttackPack =  constructor.newInstance();
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                throw new RuntimeException("没有无参构造！");
            }
            return retAttackPack;
        }
    }

    /**
     * 召唤标志
     */
    @Getter
    @AllArgsConstructor
    enum CallFlag {
        /**
         * 0:目录下所有文件
         */
        ALL_FILES(0),
        /**
         * 1:目录下满足搜索时间段的文件
         */
        TIMED_FILES(1);

        private final int val;

        public static CallFlag gain(int val) {
            for (CallFlag callFlag : CallFlag.values()) {
                if (callFlag.val == val) {
                    return callFlag;
                }
            }
            throw new EnumElemDoesNotExistException(CallFlag.class);
        }
    }

    /**
     * 文件目录召唤确认 结果描述字
     */
    @Getter
    @AllArgsConstructor
    enum FileReadDireConRD {
        /**
         * 0:成功
         */
        SUCCESS(0),
        /**
         * 1:未知错误
         */
        FAIL(1);

        private final int val;

        public static FileReadDireConRD gain(int val) {
            for (FileReadDireConRD fileReadDireConRD : FileReadDireConRD.values()) {
                if (fileReadDireConRD.val == val) {
                    return fileReadDireConRD;
                }
            }
            throw new EnumElemDoesNotExistException(FileReadDireConRD.class);
        }
    }

    /**
     * 读文件激活确认 结果描述字
     */
    @Getter
    @AllArgsConstructor
    enum FileReadConRD {
        /**
         * 0:成功
         */
        SUCCESS(0),
        /**
         * 1:未知错误
         */
        FAIL(1);

        private final int val;

        public static FileReadConRD gain(int val) {
            for (FileReadConRD fileReadConRD : FileReadConRD.values()) {
                if (fileReadConRD.val == val) {
                    return fileReadConRD;
                }
            }
            throw new EnumElemDoesNotExistException(FileReadConRD.class);
        }
    }

    /**
     * 读文件数据传输确认 结果描述字
     */
    @Getter
    @AllArgsConstructor
    enum FileRDataConRD {
        /**
         * 有后续
         */
        HAS_FOLLOW_UP(1),
        /**
         * 无后续
         */
        HAS_NO_FOLLOW_UP(0);

        private final int val;

        public static FileRDataConRD gain(int val) {
            for (FileRDataConRD fileRDataConRD : FileRDataConRD.values()) {
                if (fileRDataConRD.val == val) {
                    return fileRDataConRD;
                }
            }
            throw new EnumElemDoesNotExistException(FileRDataConRD.class);
        }
    }

    /**
     * 写文件激活确认 结果描述字
     */
    @Getter
    @AllArgsConstructor
    enum FileWriteConRD {
        /**
         * 成功
         */
        SUCCESS(0),
        /**
         * 未知错误
         */
        UNKNOWN_ERROR(1),
        /**
         * 文件名不支持
         */
        UNSUPPORTED_FILENAME(2),
        /**
         * 长度超范围
         */
        LENGTH_OUT_OF_RANGE(3);

        private final int val;

        public static FileWriteConRD gain(int val) {
            for (FileWriteConRD fileWriteConRD : FileWriteConRD.values()) {
                if (fileWriteConRD.val == val) {
                    return fileWriteConRD;
                }
            }
            throw new EnumElemDoesNotExistException(FileWriteConRD.class);
        }
    }

    /**
     * 写文件数据传输确认 结果描述字
     */
    @Getter
    @AllArgsConstructor
    enum FileWDataConRD {
        /**
         * 成功
         */
        SUCCESS(0),
        /**
         * 未知错误
         */
        UNKNOWN_ERROR(1),
        /**
         * 校验和错误
         */
        CHECKSUM_ERROR(2),
        /**
         * 文件长度不对应
         */
        UNMATCHED_FILE_LENGTH(3),
        /**
         * 文件id与激活id不一致
         */
        UNMATCHED_FILE_ID(4);

        private final int val;

        public static FileWDataConRD gain(int val) {
            for (FileWDataConRD fileWDataConRD : FileWDataConRD.values()) {
                if (fileWDataConRD.val == val) {
                    return fileWDataConRD;
                }
            }
            throw new EnumElemDoesNotExistException(FileWDataConRD.class);
        }
    }

    /**
     * 后续标志
     */
    @Getter
    @AllArgsConstructor
    enum FollowUpFlag {
        /**
         * 1为有后续
         */
        HAS_FOLLOW_UP(1),
        /**
         * 0为无后续
         */
        HAS_NO_FOLLOW_UP(0);

        private final int val;

        public static FollowUpFlag gain(int val) {
            for (FollowUpFlag followUpFlag : FollowUpFlag.values()) {
                if (followUpFlag.val == val) {
                    return followUpFlag;
                }
            }
            throw new EnumElemDoesNotExistException(FollowUpFlag.class);
        }
    }
}
